package com.lwp.excel.util;

import com.alibaba.fastjson.JSON;
import com.lwp.excel.annotation.Cell;
import com.lwp.excel.annotation.Sheet;
import com.lwp.excel.annotation.Title;
import com.lwp.excel.entity.MegedRegionCellResult;
import com.lwp.excel.exception.NotHasDataRunTimeException;
import com.lwp.excel.resolver.ExcelResolver;
import com.lwp.excel.resolver.impl.DataExcelResolver;
import com.lwp.excel.resolver.impl.SheetExcelResolver;
import lombok.Data;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Copyright (C) @2019 GuangDong Eshore Technology Co. Ltd
 *
 * @author: Administrator
 * @version: 1.0
 * @date: 2019/8/9
 * @time: 11:51
 * @description: Excel工具类，分别有Excel导入，Excel导出功能
 */
@Data
public class ExcelUtil<T> {


    /**
     * 生成Excel文件对象： 1.创建一个HSSFWorkbook，对应一个Excel文件
     * 2.第二步，在workbook中添加一个sheet,对应Excel文件中的sheet 3.在sheet中添加表头第0行,创建单元格，并设置值表头
     * 设置表头居中,注意老版本poi对Excel的行数列数有限制 4.插入数据
     *
     * @param data 需要生成Excel的数据列表
     * @param <T>
     * @return
     */
    public static <T> HSSFWorkbook exportExcel(List<T> data) {
        return exportExcel(data, (Class<?>) null);
    }

    public static <T> HSSFWorkbook exportExcel(List<T> data, Class<?> group) {
        return exportExcel(data, group, (String[]) null,null);
    }



    public static <T> HSSFWorkbook exportExcel(List<T> data, Class<?> group, List<String> headers) {
        return exportExcel(data, group, (String[]) headers.toArray(),null);
    }

    public static <T> HSSFWorkbook exportExcel(List<T> data, String title) {
        return exportExcel(data, null, (String[]) null,title);
    }


    public static <T> HSSFWorkbook exportExcel(List<T> data, Class<?> group, String title) {
        return exportExcel(data, group, (String[])null,title);
    }

    public static <T> HSSFWorkbook exportExcel(List<T> data, Class<?> group, List<String> headers,String title) {
        return exportExcel(data, group, (String[])headers.toArray(),title);
    }

    public static <T> HSSFWorkbook exportExcel(List<T> data, List<String> headers) {
        return exportExcel(data, null, (String[]) headers.toArray(),null);
    }

    public static <T> HSSFWorkbook exportExcel(List<T> data, String[] headers) {
        return exportExcel(data, null, headers,null);
    }

    /**
     * 生成Excel文件对象： 1.创建一个HSSFWorkbook，对应一个Excel文件
     * 2.第二步，在workbook中添加一个sheet,对应Excel文件中的sheet 3.在sheet中添加表头第0行,创建单元格，并设置值表头
     * 设置表头居中,注意老版本poi对Excel的行数列数有限制 4.插入数据
     *
     * @param data    需要生成的数据列表
     * @param group   生成列的分组
     * @param headers 生成列的再次筛选控制（只有使用@Cell注解标注的字段，
     *                并且headers中存在这个字段，才会显示。
     *                如果headers 为null。认为没有筛选过滤条件。显示@Cell注解的所有字段。）
     * @param <T>
     * @return
     */
    public static <T> HSSFWorkbook exportExcel(List<T> data, Class<?> group, String[] headers,String title) {
        DataExcelResolver excelResolver = new DataExcelResolver(group, headers,title);
        //检验数据
        excelResolver.checkExcel(data);
        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();
        // 第二步，生成Sheet集合，和Sheet对应的数据
        Map<HSSFSheet, List> sheetMap = excelResolver.sheetResolver(wb, data, null);
        for (HSSFSheet sheet : sheetMap.keySet()) {
            // 第三步，在sheet中添加标题,注意老版本poi对Excel的行数列数有限制
            excelResolver.titleResolver(sheet, sheetMap.get(sheet), wb, headers);
            // 第四步，在标题下面添加表头
            excelResolver.headerResolver(sheet, sheetMap.get(sheet), wb);
            // 第五步，插入数据
            excelResolver.dataResolver(sheet, sheetMap.get(sheet), wb);
            // 第六步，数据列宽自适应
            int index = excelResolver.countParticleCell(sheetMap.get(sheet).get(0).getClass(), headers);
            /*for (int i = 0; i < index; i++) {
                sheet.autoSizeColumn(i);
            }*/
            // 第七步，处理中文列宽自适应。
            setSizeColumn(sheet, index);
        }
        return wb;
    }


    private static void setSizeColumn(HSSFSheet sheet, int size) {
        int[] columnWidths = new int[size];
        //for (int columnNum = 0; columnNum < size; columnNum++) {
        //int columnWidth = sheet.getColumnWidth(columnNum) / 256;
        for (int rowNum = sheet.getLastRowNum() - 1; rowNum >= 0; rowNum--) {
            HSSFRow currentRow;
            //当前行未被使用过
            if (sheet.getRow(rowNum) == null) {
                currentRow = sheet.createRow(rowNum);
            } else {
                currentRow = sheet.getRow(rowNum);
            }
            for (int columnNum = 0; columnNum < size; columnNum++) {
                int columnWidth = sheet.getColumnWidth(columnNum) ;
                if (currentRow.getCell(columnNum) != null) {
                    HSSFCell currentCell = currentRow.getCell(columnNum);
                    if (currentCell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
                        MegedRegionCellResult megedRegionCellResult = isMergedRegionCell(sheet, rowNum, columnNum);
                        int length = currentCell.getStringCellValue().length() * 256 * 9 / 4;
                        if (megedRegionCellResult.isMerged()) {
                            //System.out.println(currentCell.getStringCellValue() + ":" + JSON.toJSONString(megedRegionCellResult));
                            int three = 0;
                            for (int i = 0; i < megedRegionCellResult.getCellMergedLength(); i++) {
                                three += columnWidths[columnNum + i];
                            }
                            if (isChangeColumnWidth(length,three)) {//需要自适应宽度
                                for (int i = 0; i < megedRegionCellResult.getCellMergedLength(); i++) {
                                    int lengthRate = length/three -1;
                                    //three += columnWidths[columnNum + i];
                                    length = columnWidths[columnNum + i] +lengthRate * columnWidths[columnNum + i];
                                    if (length > 15000) {
                                        length = 15000;
                                    }
                                    if (columnWidths[columnNum+i] < length) {
                                        columnWidths[columnNum+i] = length;
                                    }
                                }
                            }
                        }else {
                            if (columnWidth < length) {
                                columnWidth = length;
                            }
                            if (columnWidth > 15000) {
                                columnWidth = 15000;
                            }
                            if (columnWidths[columnNum] < columnWidth) {
                                columnWidths[columnNum] = columnWidth;
                            }
                        }


                    }
                }
            }
        }
        //sheet.setColumnWidth(columnNum, columnWidth * 256/5*4);
        //}
        for (int i = 0; i < size; i++) {
            sheet.setColumnWidth(i, columnWidths[i]);
        }
    }

    private static boolean isChangeColumnWidth(int length, int three) {
        return length/three > 1;
    }



    private static MegedRegionCellResult isMergedRegionCell(HSSFSheet sheet, int row, int column) {
        int sheetMergeCount = sheet.getNumMergedRegions();
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            int firstColumn = range.getFirstColumn();
            int lastColumn = range.getLastColumn();
            int firstRow = range.getFirstRow();
            int lastRow = range.getLastRow();
            if (row >= firstRow && row <= lastRow) {
                if (column >= firstColumn && column < lastColumn) {//
                    //return new Result(true, firstRow + 1, lastRow + 1, firstColumn + 1, lastColumn + 1);
                    return new MegedRegionCellResult(true, lastColumn - firstColumn + 1, lastRow - firstRow + 1, column, row);
                }
            }
        }
        return new MegedRegionCellResult(false);
    }


    public static void createExcelFile(HSSFWorkbook wb, String path) {
        OutputStream os = null;
        try {
            os = new FileOutputStream(path);
            wb.write(os);
            os.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static String getBooleanPrefix(String fieldName) {
        String prefix = fieldName.substring(0, 2);
        System.out.println(prefix);
        if (prefix.equals("is")) {
            return fieldName;
        } else {
            return "is" + getMethodName(fieldName);
        }
    }

    /**
     * 获取属性的首字母大写
     *
     * @param fildeName
     * @return
     */
    public static final String getMethodName(String fildeName) {
        byte[] items = fildeName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }

    public static void main(String[] args) {

    }


}
